/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include <malloc.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <inttypes.h>
#include <getopt.h>

#include "utils.h"
#include "bitstream.h"
#include "mpegts.h"

#include "mpegts_io.h"

#define MPEGTS_IO_READ_WAIT_COUNT			10
#define MEPGTS_IO_REGEN_EXT					"tdx"
#define MPEGTS_IO_REGEN_MAX_THREADS			2

void _mpegts_io_fflush(MPEGTS_IO_STRUCT *, FILE *);
int _mpegts_io_do_fread(FILE *, uint8_t *, uint32_t, off_t);
int _mpegts_io_do_fwrite(FILE *, uint8_t *, uint32_t);
int _mpegts_io_write_ts_nocache(MPEGTS_IO_FILEUNIT_STRUCT *, MPEGTS_IO_PACKET_STRUCT *);
int _mpegts_io_write_ts_cache(MPEGTS_IO_FILEUNIT_STRUCT *, MPEGTS_IO_PACKET_STRUCT *);
int _mpegts_io_write_ts_memory(MPEGTS_IO_FILEUNIT_STRUCT *, MPEGTS_IO_PACKET_STRUCT *);

void _mpegts_io_destroy_fileunit(MPEGTS_IO_FILEUNIT_STRUCT *, uint8_t);
uint32_t _mpegts_io_reader_shift_next_fileunit(MPEGTS_IO_READER_STRUCT *);
void _mpegts_io_fileunit_update(MPEGTS_IO_FILEUNIT_STRUCT *, MPEGTS_IO_PACKET_STRUCT *);


void *_mpegts_io_cleanup_thread(void *);
void *_mpegts_io_fixidx_thread(void *);
void * _mpegts_io_regen_idx_segment(void *);

int _mpegts_io_loadfile_idx(MPEGTS_IO_FILEUNIT_STRUCT *);
int _mpegts_io_loadfile_rec(MPEGTS_IO_FILEUNIT_STRUCT *);
int _mpegts_io_loadfile_mpg(MPEGTS_IO_FILEUNIT_STRUCT *);


// *********************************************
int _mpegts_io_do_fread(FILE *fp, uint8_t *data, uint32_t data_len, off_t pos)
{
	int ret = 0;
	if (fp && data && data_len)
	{
		int n;
		if (pos)
			fseek(fp, pos, SEEK_SET);
		n = fread(data, data_len, 1, fp);
		ret = n * data_len;
	}
	return ret;
}

int _mpegts_io_do_fwrite(FILE *fp, uint8_t *data, uint32_t data_len)
{
	int ret = 0;
	if (fp && data && data_len)
	{
		int n;
		fseek(fp, 0, SEEK_END);
		n = fwrite(data, data_len, 1, fp);
		ret = n * data_len;
//		ret = write(fileno(fp), data, data_len);
	}
	return ret;
}

int _mpegts_io_loadfile_mpg(MPEGTS_IO_FILEUNIT_STRUCT * fileunit)
{
	if (fileunit && file_exists(fileunit->ts_filename) == 0)
	{
//		printf("_mpegts_io_loadfile_mpg: %s\n", fileunit->ts_filename);
		if (fileunit->ts_fhandle)
		{
			fclose(fileunit->ts_fhandle);
			fileunit->ts_fhandle = NULL;
		}
		fileunit->ts_fhandle = fopen(fileunit->ts_filename, "rb");
		if (!fileunit->ts_fhandle)
			return -1;
		fileunit->current_file_size = get_file_size(fileunit->ts_filename);
		fileunit->max_file_size = fileunit->current_file_size + 1;
	}
	return 0;
}
int _mpegts_io_loadfile_idx(MPEGTS_IO_FILEUNIT_STRUCT * fileunit)
{
	if (fileunit && file_exists(fileunit->idx_filename) == 0)
	{
		struct stat file_stat = {0};
//		printf("_mpegts_io_loadfile_idx: %s\n", fileunit->idx_filename);
		stat(fileunit->idx_filename, &file_stat);

		_mpegts_io_loadfile_rec(fileunit);

		if (fileunit->idx_mtime && fileunit->idx_ctime)
		{
			if (fileunit->idx_mtime == file_stat.st_mtime ||
				fileunit->idx_ctime == file_stat.st_ctime)
			{
//				printf("[TS_IO] m/ctime matches, not updating\n");
				return 0;
			}
		}
//		printf("[TS_IO] ctime: %" PRId64 "(%"PRId64"), mtime: %" PRId64"(%" PRId64")\n", file_stat.st_ctime, fileunit->idx_ctime, file_stat.st_mtime, fileunit->idx_mtime);

		fileunit->idx_mtime = file_stat.st_mtime;
		fileunit->idx_ctime = file_stat.st_ctime;


		fileunit->idx_fhandle = fopen(fileunit->idx_filename, "rb");
		if (fileunit->idx_fhandle)
		{
			if (fileunit->first_idx)
			{
				MPEGTS_IO_IDXUNIT_STRUCT * _idx = fileunit->first_idx;
				MPEGTS_IO_IDXUNIT_STRUCT * _del = NULL;
//				printf("_mpegts_io_loadfile_idx, freeing indexes\n");

				while(_idx)
				{
					_del = _idx;
					_idx = _idx->next;
					if (_del)
						free(_del);
				}
				fileunit->first_idx = fileunit->current_idx = fileunit->last_idx = NULL;
			}

			if (get_file_size(fileunit->idx_filename) == 0)
			{
				fileunit->first_idx = fileunit->current_idx = fileunit->last_idx = NULL;
				fileunit->first_pts = 0;
				fclose(fileunit->idx_fhandle);
				fileunit->idx_fhandle = 0;
				return 0;
			}


			while(!feof(fileunit->idx_fhandle))
			{
				uint16_t _t;
				int r;
				MPEGTS_IO_IDXUNIT_STRUCT * _idx  = calloc(1, sizeof(MPEGTS_IO_IDXUNIT_STRUCT));
				if (_idx)
				{
					r = _mpegts_io_do_fread(fileunit->idx_fhandle, (uint8_t*)&_t, sizeof(_t), 0);
//					printf("MOO: %d\n", r);
					if (r && _t == TS_IO_IDX_HEADER)
					{
						_mpegts_io_do_fread(fileunit->idx_fhandle, (uint8_t*)&_idx->packet_number, sizeof(_idx->packet_number), 0);
						_mpegts_io_do_fread(fileunit->idx_fhandle, (uint8_t*)&_idx->pts, sizeof(_idx->pts), 0);
						_mpegts_io_do_fread(fileunit->idx_fhandle, (uint8_t*)&_idx->dts, sizeof(_idx->dts), 0);


						if (fileunit->first_idx)
						{
							if (_idx->pts && fileunit->first_idx->pts > _idx->pts)
								if (fileunit->first_idx->pts - _idx->pts >= 90000 * 2)
									_idx->pts += MAX_33BITS;

							if (_idx->dts && fileunit->first_idx->pts > _idx->dts)
								if (fileunit->first_idx->pts - _idx->dts >= 90000 * 2)
									_idx->dts += MAX_33BITS;
						}
//						printf("idx, packet num: %" PRId64" -- PTS: %0.2f, DTS: %0.2f\n", _idx->packet_number, _idx->pts/90000.0, _idx->pts/90000.0);
						if (!fileunit->first_idx)
						{
							fileunit->first_idx = fileunit->current_idx = _idx;
						}
						else
						{
							fileunit->current_idx->next = _idx;
							fileunit->current_idx = _idx;
						}
					}
					else
					{
						free(_idx);
/*
						if (_t != TS_IO_IDX_HEADER)
							printf("NOT A IDX: %s\n", fileunit->idx_filename);
*/
//						return -1;
					}
				}
				else
				{
					printf("BIG ERRORS\n");
					return -1;
				}
			}
			fclose(fileunit->idx_fhandle);
			fileunit->idx_fhandle = 0;
//			printf("first idx, packet num: %" PRId64" (%" PRId64") -- PTS: %0.2f, DTS: %0.2f\n", fileunit->first_idx->packet_number,fileunit->first_idx->packet_number * TS_PACKET_SIZE, fileunit->first_idx->pts/90000.0, fileunit->first_idx->pts/90000.0);
//			printf("last idx, packet num: %" PRId64" (%" PRId64") -- PTS: %0.2f, DTS: %0.2f\n", fileunit->current_idx->packet_number,fileunit->current_idx->packet_number * TS_PACKET_SIZE, fileunit->current_idx->pts/90000.0, fileunit->current_idx->pts/90000.0);
		}
	}
	return 0;
}

int mpegts_io_regen_idx(char *basefilename, int show_status, int stop_count)
{
	if (basefilename)
	{
		uint64_t idx_count = 0;
		uint32_t last_frame_sz = TS_PACKET_SIZE * 10;
		uint8_t *last_frame_data = calloc(1, last_frame_sz);
		uint32_t last_frame_pos = 0;

		char mpg_filename[8096] = {0};
		char idx_filename[8096] = {0};
		snprintf(mpg_filename, 8095, "%s.mpg", basefilename);
		snprintf(idx_filename, 8095, "%s.%s", basefilename, MEPGTS_IO_REGEN_EXT);

		printf("[TS_IO] Regen:\n");
		printf("\tMPG: %s\n", mpg_filename);
		printf("\tIDX: %s\n", idx_filename);

    	if (file_exists(mpg_filename) == 0)
		{
			off_t file_sz = get_file_size(mpg_filename);

			size_t alloc_sz = (TS_PACKET_SIZE * 2000);
			uint8_t *data = malloc(alloc_sz);
//			printf("H1\n");
			if (data)
			{
				uint8_t frame_type = 0;

//				uint8_t video_type = 0;
				uint64_t start_pts = 0;
				uint64_t packet_count = 0;
				int q;
				uint8_t start = 0;
				uint16_t pid = 0, video_pid = 0;
//				uint8_t af = 0;
//				size_t fret = 0;
				BITSTREAM *bitstream = NULL;
				MPEGTS_IO_IDXUNIT_STRUCT *_idx= calloc(1, sizeof(MPEGTS_IO_IDXUNIT_STRUCT));
				MPEGTS_PARSE_STRUCT parser = {0};

//				FILE *mpg_file = fopen(mpg_filename, "rb");
				int mpg_fileh = open(mpg_filename, O_RDONLY);
				FILE *idx_file = fopen(idx_filename, "wr");

				while(read(mpg_fileh, data, alloc_sz) > 0)
				{
					for(q=0; q < alloc_sz; q += TS_PACKET_SIZE)
					{
						if (data[q] == TS_SYNC_BYTE)
						{
							packet_count++;
							pid = ((data[q+1] & 0x1F) << 8) | data[q+2];
//							if (pid == 0)
//								printf("PPPPAAAAAAAAAAA\n");
//							printf("PID: 0x%x (vpid: 0x%x)\n", pid, video_pid);
							if (video_pid && video_pid != pid)
								continue;

							start = (data[q+1] & 0x40) >> 6;

							if (start)
							{
//								printf("START\n");
								bitstream = bits_create(&data[q], TS_PACKET_SIZE);
								if (bitstream)
								{
									int i;
									MPEGTS_PACKET *packet = mpegts_parse_packet2(bitstream, &parser);
									if (packet)
									{
//								printf("START : 0x%x 0x%x\n", parser.stream_type, parser.pmt_type);
										if (parser.stream_type && parser.pmt_type)
										{
											uint8_t do_write = 0;

											if (parser.stream_type >= MPEGTS_VIDEO_STREAM_START && parser.stream_type <= MPEGTS_VIDEO_STREAM_END)
											{
												video_pid = packet->pid;
												switch(parser.pmt_type)
												{
													case MPEGTS_STREAM_TYPE_ISO14496_10:
													{
														for (i = bitstream->bit_offset/8; i < TS_PACKET_SIZE-4; i++)
														{
															if (data[q+i] == 0x00 && data[q+i+1] == 0x00 && data[q+i+2] == 0x01)
															{
																uint8_t nal_type = data[q+i+3] & 0x1F;

																if (nal_type == 0x05) // IDR, write
																{
																	do_write = 1;
																}
																else if (nal_type == 0x09)
																{
																	uint8_t pp = data[i+4] >> 5;
																	if (pp == 1 || pp == 0)
																		do_write = 1;
//																	printf("PP: %d (%d)\n", pp, do_write);
																}
															}
														}
//														printf("[0x%x] H264 Video -- PTS: %" PRId64" (%0.2f), DTS: %" PRId64" (%0.2f)\n",packet->pid, packet->payload_start_struct->pts, packet->payload_start_struct->pts/90000.0, packet->payload_start_struct->dts, packet->payload_start_struct->dts/90000.0);
													}
													break;

													case MPEGTS_STREAM_TYPE_ISO13818_V:
													case MPEGTS_STREAM_TYPE_SOMETHING:
													{
//														uint8_t haz = 0;
//														printf("MPEG2\n");

														if (last_frame_pos)
														{
															for(i=0; i < last_frame_sz; i++)
															{
																if (last_frame_data[i] == 0x00 &&  last_frame_data[i+1] == 0x00 &&  last_frame_data[i+2] == 0x01)
																{
																	if (last_frame_data[i+3] == 0x00)
																	{
//																		haz = 1;
//																		m->temporal_reference = ((uint16_t)tmp_buf[0] << 2) | ((uint16_t)tmp_buf[1] >> 6);
																		frame_type = (uint8_t) (last_frame_data[i+5] & 0x38) >> 3;
																		if (frame_type <= 2)
																		{
																			do_write = 1;
//																			printf("Frame Type: 0x%x\n", frame_type);
//																			printf("[0x%x] MPEG2 Video -- PTS: %" PRId64" (%0.2f), DTS: %" PRId64" (%0.2f)\n",packet->pid, _idx->pts, _idx->pts/90000.0, _idx->dts, _idx->dts/90000.0);
//																			printf("[0x%x] MPEG2 Video -- PTS: %" PRId64", DTS: %" PRId64"\n",packet->pid, _idx->pts, _idx->dts);
//																			printf("\tSTART CODE: 0x%x, FrameType: %d\n",  last_frame_data[i+3], frame_type);
																		}
	
																	}
																}
															}
															last_frame_pos = 0;
														}

														i = bitstream->bit_offset/8;
														if (last_frame_pos + (TS_PACKET_SIZE - i) < last_frame_sz)
														{
															memcpy(&last_frame_data[last_frame_pos], &bitstream->stream[i], TS_PACKET_SIZE - i);
															last_frame_pos += (TS_PACKET_SIZE - i);
														}

														//	printf("Video Start, no PC\n");
													}

													break;
												}

											}

											if (do_write)
											{
												uint16_t _t = TS_IO_IDX_HEADER;

												_idx->packet_number = packet_count;
												if (!start_pts)
													start_pts = packet->payload_start_struct->pts;

												_idx->pts = packet->payload_start_struct->pts;
												_idx->dts = packet->payload_start_struct->pts;

												if (!_idx->dts)
													_idx->dts = _idx->pts;

												if (_idx->pts && start_pts > _idx->pts)
												{
													if (start_pts - _idx->pts >= 90000 * 2)
														_idx->pts += MAX_33BITS;
												}

												if (_idx->dts && start_pts > _idx->dts)
												{
													if (start_pts - _idx->dts >= 90000 * 2)
														_idx->dts += MAX_33BITS;
												}
//												last_pts = _idx->pts;

//												printf("[0x%x] Writing Video -- PTS: %" PRId64" (%0.2f), DTS: %" PRId64" (%0.2f)\n",packet->pid, _idx->pts, _idx->pts/90000.0, _idx->dts, _idx->dts/90000.0);
												 _mpegts_io_do_fwrite(idx_file, (uint8_t*)&_t, sizeof(_t));
												 _mpegts_io_do_fwrite(idx_file, (uint8_t*)&_idx->packet_number, sizeof(_idx->packet_number));
												 _mpegts_io_do_fwrite(idx_file, (uint8_t*)&_idx->pts, sizeof(_idx->pts));
												 _mpegts_io_do_fwrite(idx_file, (uint8_t*)&_idx->dts, sizeof(_idx->dts));
												idx_count++;

												if (show_status)
												{
													printf("  %0.0f\r", ((_idx->packet_number * TS_PACKET_SIZE)/(double)file_sz) * 100.0);
													fflush(stdout);
												}
											}
										}
										else
										{
//											printf("BLAH\n");
										}
/*
										if (parser.pmt)
										{
											mpegts_free_pmt(parser.pmt);
											parser.pmt = NULL;
										}

										if (parser.pat)
										{
											mpegts_free_pat(parser.pat);
											parser.pat = NULL;
										}
*/
										mpegts_free_packet(packet);

									}
									else
									{
										printf("BLAH2\n");
									}
									free(bitstream);
								}
							}
							else
							{
								if (video_pid)
								{
									if (last_frame_pos + (TS_PACKET_SIZE - 4) < last_frame_sz)
									{
										memcpy(&last_frame_data[last_frame_pos], &data[q+4], TS_PACKET_SIZE - 4);
										last_frame_pos += (TS_PACKET_SIZE - 4);
									}
								}
									// Add to last_data
							}
							//packet_count++;
						}
						else
							printf("NO SYNC]\n");
					}
					if (stop_count && idx_count >= stop_count)
						break;
				}

				if (_idx)
					free(_idx);
				close(mpg_fileh);
				fclose(idx_file);
				free(data);
				snprintf(mpg_filename, 8095, "%s.idx", basefilename);
				if (last_frame_data)
					free(last_frame_data);

				return rename(idx_filename, mpg_filename);
			}

		}
		else
		{
			printf("[TS_IO] NO FILE\n");
		}
		if (last_frame_data)
			free(last_frame_data);
	}
	return 0;
}

UTILS_DATAPAIR_STRUCT * mpegts_io_get_rec_data(MPEGTS_IO_STRUCT *mpegts_io)
{
	if (mpegts_io)
	{
		if (mpegts_io->extra_data[0])
			return mpegts_io->extra_data[0];
		else if (mpegts_io->first_fileunit)
			return mpegts_io->first_fileunit->extra_data[0];
	}
	return NULL;
}
int _mpegts_io_loadfile_rec(MPEGTS_IO_FILEUNIT_STRUCT * fileunit)
{
	if (fileunit && file_exists(fileunit->rec_filename) == 0)
	{
		off_t sz = 0;
//		printf("_mpegts_io_loadfile_rec: %s\n", fileunit->rec_filename);

		struct stat file_stat = {0};
//		printf("_mpegts_io_loadfile_idx: %s\n", fileunit->idx_filename);
		stat(fileunit->rec_filename, &file_stat);

		if (fileunit->rec_mtime && fileunit->rec_ctime)
		{
			if (fileunit->rec_mtime == file_stat.st_mtime ||
				fileunit->rec_ctime == file_stat.st_ctime)
			{
//				printf("[TS_IO] m/ctime matches, not updating\n");
				return 0;
			}
		}


		fileunit->rec_mtime = file_stat.st_mtime;
		fileunit->rec_ctime = file_stat.st_ctime;


		sz = get_file_size(fileunit->rec_filename);
		if (sz > 0)
		{
			int fh = 0, bytes_read = 0;
			UTILS_DATAPAIR_STRUCT *tmp_data = NULL;
			MPEGTS_IO_STRUCT *mpegts_io = (MPEGTS_IO_STRUCT *)fileunit->parent;

			if (fileunit->extra_data[0])
			{
				if (fileunit->extra_data[0]->data)
					free(fileunit->extra_data[0]->data);

				free(fileunit->extra_data[0]);
				fileunit->extra_data[0] = NULL;
			}

			fh = open(fileunit->rec_filename, O_RDONLY);

			tmp_data = malloc(sizeof(UTILS_DATAPAIR_STRUCT));

			tmp_data->data = malloc(sz);
			tmp_data->data_size = sz;

			if (mpegts_io)
			{
//				printf("Setting parent\n");
				mpegts_io->extra_data[0] = tmp_data;
			}
			else
			{
//				printf("Setting fileunit\n");
				fileunit->extra_data[0] = tmp_data;
			}

			if (fh > 2)
			{
				bytes_read = get_bytes_from_file(fh, tmp_data->data, sz);
				if (bytes_read != sz)
				{
					printf("READ ERRORORORORO: %d\n", bytes_read);
					return -1;
				}
//				printf("_mpegts_io_loadfile_rec [%s] loaded: %d\n",  fileunit->rec_filename, bytes_read);
				close(fh);
			}
		}
	}
	return 0;
}

void _mpegts_io_destroy_fileunit(MPEGTS_IO_FILEUNIT_STRUCT *fileunit, uint8_t remove_files)
{
	if (fileunit)
	{
		int i;
		MPEGTS_IO_IDXUNIT_STRUCT * del_idx;

//		printf("[TS_IO] destroying fileunit (%s) (%s)\n", fileunit->ts_filename, fileunit->idx_filename);

		if (fileunit->memory_handle)
		{
			free(fileunit->memory_handle);
			fileunit->memory_handle = NULL;
		}

		if (fileunit->ts_fhandle)
		{
			fclose(fileunit->ts_fhandle);
			fileunit->ts_fhandle = NULL;
		}

		if (fileunit->ts_filename)
		{
			if (remove_files)
				remove(fileunit->ts_filename);
			free(fileunit->ts_filename);
			fileunit->ts_filename = NULL;
		}


		if (fileunit->idx_fhandle)
		{
			fclose(fileunit->idx_fhandle);
			fileunit->idx_fhandle = NULL;
		}

		if (fileunit->idx_filename)
		{
			if (remove_files)
				remove(fileunit->idx_filename);
			free(fileunit->idx_filename);
			fileunit->idx_filename = NULL;
		}


		if (fileunit->rec_fhandle)
		{
			fclose(fileunit->rec_fhandle);
			fileunit->rec_fhandle = NULL;
		}

		if (fileunit->rec_filename)
		{
			if (remove_files)
				remove(fileunit->rec_filename);
			free(fileunit->rec_filename);
			fileunit->rec_filename = NULL;
		}

		if (fileunit->update_lock_attr)
			pthread_mutexattr_destroy(fileunit->update_lock_attr);

		pthread_mutex_destroy(&fileunit->update_lock);

// free the index list
		fileunit->current_idx = fileunit->first_idx;

		while(fileunit->current_idx)
		{
			del_idx = fileunit->current_idx;
			fileunit->current_idx = fileunit->current_idx->next;
			free(del_idx);
		}

		for(i=0; i < MPEGTS_IO_FILEUNIT_EXTRA_COUNT; i++)
		{
			if (fileunit->extra_data[i])
				utils_free_datapair(fileunit->extra_data[i]);
		}
//		printf("[TS_IO] Dest. Exit\n");
//		pthread_mutex_unlock(&mpegts_io->update_lock);
	}
}

void _mpegts_io_print_idxs(MPEGTS_IO_FILEUNIT_STRUCT *fileunit)
{
	if (fileunit)
	{
		MPEGTS_IO_IDXUNIT_STRUCT *_idx = fileunit->first_idx;
		printf("[TS_IO] print_idxs, idx count: %d\n", fileunit->index_count);
		while (_idx)
		{
			printf("[TS_IO] Packet #: %" PRId64" (PTS: %" PRId64" [%0.4f], DTS: %" PRId64" [%0.4f])\n", _idx->packet_number,  _idx->pts, _idx->pts/90000.0, _idx->dts, _idx->dts/90000.0);
			_idx = _idx->next;
		}
	}
	return;
}

void _mpegts_io_fileunit_update(MPEGTS_IO_FILEUNIT_STRUCT *fileunit, MPEGTS_IO_PACKET_STRUCT *packet)
{
	if (fileunit && packet)
	{
		MPEGTS_IO_STRUCT *mpegts_io = (MPEGTS_IO_STRUCT *)fileunit->parent;

		if (!fileunit->memory_handle && fileunit->ts_fhandle <= 0)
		{
			fileunit->update_lock_attr = calloc(1, sizeof(*fileunit->update_lock_attr));
			utils_mutex_init(&fileunit->update_lock, fileunit->update_lock_attr, PTHREAD_MUTEX_RECURSIVE);

			fileunit->packet_count = 0;
			fileunit->current_file_size = 0;
			fileunit->max_file_size = mpegts_io->max_file_size;

			if (mpegts_io->use_mem_only)
			{
				fileunit->memory_handle = calloc(1, fileunit->max_file_size);
			}
			else
			{
				fileunit->ts_filename = calloc(1, MAX_FILENAME_SIZE);
				fileunit->idx_filename = calloc(1, MAX_FILENAME_SIZE);

				if (fileunit->max_file_size)
				{
					snprintf(fileunit->ts_filename, MAX_FILENAME_SIZE,"%s_%010d.mpg", mpegts_io->base_filename, fileunit->id);
					snprintf(fileunit->idx_filename, MAX_FILENAME_SIZE,"%s_%010d.idx", mpegts_io->base_filename, fileunit->id);
				}
				else
				{
					snprintf(fileunit->ts_filename, MAX_FILENAME_SIZE,"%s.mpg", mpegts_io->base_filename);
					snprintf(fileunit->idx_filename, MAX_FILENAME_SIZE,"%s.idx", mpegts_io->base_filename);
//					printf("M1: %s\n", fileunit->ts_filename);
//					printf("M2: %s\n", fileunit->idx_filename);
				}

				if (fileunit->ts_filename && fileunit->idx_filename)
				{
					fileunit->ts_fhandle = fopen(fileunit->ts_filename, "wb+");
					fileunit->idx_fhandle = fopen(fileunit->idx_filename, "wb+");

/*
//					int tmph = 0, flags=0;
					if (setvbuf (fileunit->ts_fhandle , NULL , _IONBF , BUFSIZ * 5) != 0)
						printf("setvbuf failed1!\n");
					if (setvbuf (fileunit->idx_fhandle , NULL , _IONBF , BUFSIZ * 5) != 0)
						printf("setvbuf failed2!\n");
*/
				}
			}
		}

		if (fileunit->ts_fhandle || fileunit->memory_handle)
		{
//			printf("huh: %d %d %"PRId64" -- %" PRId64"\n", packet->pid, mpegts_io->video_pid, packet->pts, packet->dts);
			if (packet->pid && packet->pts)
			{
				if (fileunit->first_pts == 0 || packet->pts < fileunit->first_pts)
				{
//					printf("setting firstpts: %" PRId64" (%0.2f) -- old: %" PRId64" (%0.2f)\n", packet->pts, packet->pts/90000.0, fileunit->first_pts, fileunit->first_pts/90000.0);
					fileunit->first_pts  = packet->pts;
				}
			}

			if (packet->pid == mpegts_io->video_pid && (packet->pts || packet->dts))
			{
//				printf("HMM[frtype: 0x%x]: %d %d %" PRId64" (%0.2f)\n",packet->frame_type,  packet->pid, mpegts_io->video_pid, packet->pts, packet->pts/90000.0);
 				if (packet->frame_type == 1)
				{
					MPEGTS_IO_IDXUNIT_STRUCT * _idx  = calloc(1, sizeof(MPEGTS_IO_IDXUNIT_STRUCT));

					if (_idx)
					{
//						printf("IDX1 -- %" PRId64" -- %" PRId64"\n", _idx->packet_number, fileunit->packet_count);
						_idx->pts = packet->pts;
						_idx->dts = packet->dts;
						_idx->packet_number = fileunit->packet_count;


						if (fileunit->first_idx)
						{
							if (_idx->pts && fileunit->first_idx->pts > _idx->pts)
								if (fileunit->first_idx->pts - _idx->pts >= 90000 * 2)
									_idx->pts += MAX_33BITS;

							if (_idx->dts && fileunit->first_idx->pts > _idx->dts)
								if (fileunit->first_idx->pts - _idx->dts >= 90000 * 2)
									_idx->dts += MAX_33BITS;
						}

						if (!fileunit->first_idx)
						{
							fileunit->first_idx = fileunit->current_idx = _idx;
						}
						else
						{
							fileunit->current_idx->next = _idx;
							fileunit->current_idx = _idx;
						}

						if (!fileunit->idx_fhandle)
							fileunit->idx_fhandle = fopen(fileunit->idx_filename, "wb+");

						if (fileunit->idx_fhandle)
						{
							uint16_t _t = TS_IO_IDX_HEADER;
							fileunit->last_idx_pts = _idx->pts;
//							printf("1\n");
//							printf("Writing IDX: %" PRId64" (%0.2f -- %0.2f)\n", _idx->packet_number, _idx->pts/90000.0, _idx->dts/90000.0);
							 _mpegts_io_do_fwrite(fileunit->idx_fhandle, (uint8_t*)&_t, sizeof(_t));
							 _mpegts_io_do_fwrite(fileunit->idx_fhandle, (uint8_t*)&_idx->packet_number, sizeof(_idx->packet_number));
							 _mpegts_io_do_fwrite(fileunit->idx_fhandle, (uint8_t*)&_idx->pts, sizeof(_idx->pts));
							 _mpegts_io_do_fwrite(fileunit->idx_fhandle, (uint8_t*)&_idx->dts, sizeof(_idx->dts));
//							 _mpegts_io_do_fwrite(fileunit->idx_fhandle, (uint8_t*)_idx, sizeof(MPEGTS_IO_IDXUNIT_STRUCT));
						}
					}
				}
			}
			else
			{
//				printf("BAD: %d %d -- %" PRId64" : %" PRId64"\n", packet->pid, mpegts_io->video_pid , packet->pts, packet->dts);
			}
		}
	}
}

int _mpegts_io_write_ts_memory(MPEGTS_IO_FILEUNIT_STRUCT *fileunit, MPEGTS_IO_PACKET_STRUCT *packet)
{
	MPEGTS_IO_STRUCT *mpegts_io = (MPEGTS_IO_STRUCT *)fileunit->parent;

	if (fileunit->memory_handle)
	{
		pthread_mutex_lock(&fileunit->update_lock);
		memcpy(fileunit->memory_handle + fileunit->current_file_size, packet->data, packet->data_len);
//		fwrite(fileunit->memory_handle + fileunit->current_file_size, packet->data_len, 1, tmpfp);
		fileunit->current_file_size += packet->data_len;
		pthread_mutex_unlock(&fileunit->update_lock);

		if (fileunit->current_file_size == fileunit->max_file_size)
		{
			MPEGTS_IO_FILEUNIT_STRUCT *newfileunit = calloc(1, sizeof(MPEGTS_IO_FILEUNIT_STRUCT));

			if (newfileunit)
			{
				newfileunit->parent = mpegts_io;
				newfileunit->id = fileunit->id + 1;
				newfileunit->max_file_size = mpegts_io->max_file_size;

				mpegts_io->current_fileunit->next = newfileunit;
				mpegts_io->current_fileunit->last_idx = mpegts_io->current_fileunit->current_idx;
				fileunit = mpegts_io->current_fileunit  = newfileunit;
				_mpegts_io_fileunit_update(fileunit, packet);
			}
		}
	}
	else
	{
		printf("jjjjjjj\n");
	}
	return 0;
}

void _mpegts_io_fflush(MPEGTS_IO_STRUCT *mpegts_io, FILE *fp)
{
	if (mpegts_io)
	{
		int64_t now = (int64_t)time(NULL);
		if (now - mpegts_io->last_flush_time > 6)
		{
			mpegts_io->last_flush_time = now;
			printf("FLUSING!\n");
			fflush(fp);
		}
	}
}
int _mpegts_io_write_ts_nocache(MPEGTS_IO_FILEUNIT_STRUCT *fileunit, MPEGTS_IO_PACKET_STRUCT *packet)
{
	MPEGTS_IO_STRUCT *mpegts_io = (MPEGTS_IO_STRUCT *)fileunit->parent;
//	printf("_mpegts_io_write_ts_nocache\n");
	if (fileunit->ts_fhandle)
	{
		pthread_mutex_lock(&fileunit->update_lock);
		_mpegts_io_do_fwrite(fileunit->ts_fhandle, packet->data, packet->data_len);
		//_mpegts_io_fflush(mpegts_io, fileunit->ts_fhandle);
		fileunit->current_file_size += packet->data_len;
		fileunit->packet_count = (fileunit->current_file_size/TS_PACKET_SIZE);
		pthread_mutex_unlock(&fileunit->update_lock);

		if (fileunit->max_file_size && fileunit->current_file_size == fileunit->max_file_size)
		{
			MPEGTS_IO_FILEUNIT_STRUCT *newfileunit = calloc(1, sizeof(MPEGTS_IO_FILEUNIT_STRUCT));

			if (newfileunit)
			{
				newfileunit->parent = mpegts_io;
				newfileunit->id = fileunit->id + 1;
				newfileunit->max_file_size = mpegts_io->max_file_size;

				mpegts_io->current_fileunit->next = newfileunit;
				mpegts_io->current_fileunit->last_idx = mpegts_io->current_fileunit->current_idx;
				fileunit = mpegts_io->current_fileunit  = newfileunit;
				_mpegts_io_fileunit_update(fileunit, packet);
			}
		}
	}
	else
	{
		printf("JJJJJJJJJJ\n");
	}
	return 0;
}


int _mpegts_io_write_ts_cache(MPEGTS_IO_FILEUNIT_STRUCT *fileunit, MPEGTS_IO_PACKET_STRUCT *packet)
{
	int ret = 0;
	MPEGTS_IO_STRUCT *mpegts_io = (MPEGTS_IO_STRUCT *)fileunit->parent;

	if (mpegts_io->write_cache_pos < mpegts_io->write_cache_size)
	{
		memcpy(mpegts_io->write_cache + mpegts_io->write_cache_pos, packet->data, packet->data_len);
		mpegts_io->write_cache_pos += packet->data_len;
	}

	if (!fileunit->ts_fhandle)
		return ret;

	if (mpegts_io->write_cache_pos == mpegts_io->write_cache_size)
	{
		uint32_t _cache_size = mpegts_io->write_cache_size;
		uint32_t _cache_offset = 0;

		if (fileunit->max_file_size && (fileunit->current_file_size + _cache_size > fileunit->max_file_size))
			_cache_size = fileunit->max_file_size - fileunit->current_file_size;

		pthread_mutex_lock(&fileunit->update_lock);
		_mpegts_io_do_fwrite(fileunit->ts_fhandle, mpegts_io->write_cache, _cache_size);
		//_mpegts_io_fflush(mpegts_io, fileunit->ts_fhandle);
		fileunit->current_file_size += _cache_size;
		fileunit->packet_count += (_cache_size/TS_PACKET_SIZE);
		_cache_offset = _cache_size;
		pthread_mutex_unlock(&fileunit->update_lock);

		if (fileunit->max_file_size && fileunit->current_file_size == fileunit->max_file_size)
		{
			MPEGTS_IO_FILEUNIT_STRUCT *newfileunit = calloc(1, sizeof(MPEGTS_IO_FILEUNIT_STRUCT));

			if (newfileunit)
			{
				fclose(fileunit->ts_fhandle);
				fileunit->ts_fhandle  = fopen(fileunit->ts_filename, "rb");
				malloc_trim(0);
/*
//				printf("Closing/reopening fhandles...\n");
//				fflush(fileunit->ts_fhandle);
//				fsync(fileno(fileunit->ts_fhandle));
//				sync();

				fclose(fileunit->idx_fhandle);
				fileunit->idx_fhandle  = fopen(fileunit->idx_filename, "rb");

*/
				newfileunit->parent = mpegts_io;
				newfileunit->id = fileunit->id + 1;
				newfileunit->max_file_size = mpegts_io->max_file_size;

				mpegts_io->current_fileunit->next = newfileunit;
				mpegts_io->current_fileunit->last_idx = mpegts_io->current_fileunit->current_idx;
				fileunit = mpegts_io->current_fileunit  = newfileunit;
				_mpegts_io_fileunit_update(fileunit, packet);
			}
		}

        if (_cache_size < mpegts_io->write_cache_size)
        {
            _cache_size = mpegts_io->write_cache_size - _cache_offset;
			pthread_mutex_lock(&fileunit->update_lock);
			_mpegts_io_do_fwrite(fileunit->ts_fhandle, mpegts_io->write_cache + _cache_offset, _cache_size);
			//_mpegts_io_fflush(mpegts_io, fileunit->ts_fhandle);
            fileunit->current_file_size += _cache_size;
            fileunit->packet_count += (_cache_size/TS_PACKET_SIZE);
			pthread_mutex_unlock(&fileunit->update_lock);

        }
        mpegts_io->write_cache_pos = 0;
        ret = mpegts_io->write_cache_size;
	}

	return ret;
}

uint32_t mpegts_io_get_packet_remaining_fileunit(MPEGTS_IO_READER_STRUCT * reader)
{
//	MPEGTS_IO_STRUCT *mpegts_io = NULL;
	uint32_t packets_left = 0;
	if (reader->fileunit)
	{
//		mpegts_io = (MPEGTS_IO_STRUCT *)reader->fileunit->parent;
		packets_left = (reader->fileunit->current_file_size / TS_PACKET_SIZE) - reader->packet_index;
/*
		if (packets_left == 0 && mpegts_io && mpegts_io->write_cache)
		{
			printf("HERE! %d (%0.2f)\n", mpegts_io->write_cache_pos, mpegts_io->write_cache_pos/188.0);
//			packets_left = mpegts_io->write_cache_pos/TS_PACKET_SIZE;
		}
*/
	}
	return packets_left;
}

uint32_t mpegts_io_get_packet_remaining(MPEGTS_IO_READER_STRUCT * reader)
{
	uint32_t packets_left = 0;

	if (reader && reader->parent)
	{
		uint32_t count = 0;
//		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		MPEGTS_IO_FILEUNIT_STRUCT *fileunit = reader->fileunit;
		uint32_t reader_index = reader->packet_index;

		while (fileunit)
		{
			while(fileunit->current_file_size <= 0)
			{
//				printf("HERE1\n");
				usleep(1000*500);
				count++;
				if (count > 4)
					return 0;
			}
			packets_left += (fileunit->current_file_size / TS_PACKET_SIZE) - reader_index;
			fileunit = fileunit->next;
			reader_index = 0;
		}
	}
	return packets_left;
}


uint32_t _mpegts_io_reader_shift_next_fileunit(MPEGTS_IO_READER_STRUCT * reader)
{
	uint8_t ret = 0;
	if (reader && reader->fileunit && reader->fileunit->next)
	{
		reader->fileunit->reader_count--;
		reader->packet_index = 0;
		reader->fileunit = reader->fileunit->next;

		reader->fileunit->reader_count++;

		ret = (reader->fileunit->current_file_size / TS_PACKET_SIZE) - reader->packet_index;
	}
	return ret;
}

uint32_t mpegts_io_get_packet_count(MPEGTS_IO_READER_STRUCT * reader, uint32_t count)
{
	uint32_t ret = 0;

	if (reader && reader->fileunit)
	{
		uint32_t packets_left = mpegts_io_get_packet_remaining_fileunit(reader);

		if (packets_left == 0)
		{
//			printf("!!!!!!!!!!!!!!!!!!!!!!\n");
			if (reader->fileunit->current_file_size >= reader->fileunit->max_file_size)
			{
//				printf("Shifting..\n");
				packets_left = _mpegts_io_reader_shift_next_fileunit(reader);
			}
			else
			{
//				printf("NOT Shifting : %" PRId64" %" PRId64"\n", reader->fileunit->current_file_size, reader->fileunit->max_file_size);
//				printf("MOO? %d %d\n", 
				return 0;
			}
		}
//		printf("mpegts_io_get_packet_count: 2\n");

		if (count > packets_left)
			count = packets_left;

		if (count == 0)
			return 0;

		ret = reader->data_len = (TS_PACKET_SIZE * count);

//		printf("mpegts_io_get_packet_count: 3\n");

		if (reader->fileunit->memory_handle)
		{
			if (!memcpy(reader->data, reader->fileunit->memory_handle + (reader->packet_index * TS_PACKET_SIZE), reader->data_len))
				ret = reader->data_len;
		}
		else if (reader->fileunit->ts_fhandle)
		{
			int _rc = 0, i = 0, n;
			struct timespec wait = {0};

			wait.tv_sec = 1;

//			_rc = pthread_mutex_lock(&reader->fileunit->update_lock);
			for (i = 0; i <  MPEGTS_IO_READ_WAIT_COUNT; i++)
			{
				_rc = pthread_mutex_timedlock(&reader->fileunit->update_lock, &wait);
//				_rc = pthread_mutex_trylock(&reader->fileunit->update_lock);
				if (_rc == 0)
					break;
				else
					usleep(1000);
//				printf("Waiting for reader_lock, count: %d (%d -- %s)\n", i, _rc, strerror(errno));
//				usleep(1000);
			}

			if (i >= MPEGTS_IO_READ_WAIT_COUNT)
			{
//				printf("Waiting for reader_lock  -- EXIT -- %d %d (count: %d)\n", _rc, fileno(reader->ts_fhandle), i);
				return 0;
			}

			reader->ts_fhandle = reader->fileunit->ts_fhandle;
//			pos = ftell(reader->ts_fhandle);
			fseek(reader->ts_fhandle, reader->packet_index * TS_PACKET_SIZE, SEEK_SET);
			n = fread(reader->data, reader->data_len, 1, reader->ts_fhandle);
//			fseek(reader->ts_fhandle, pos, SEEK_SET);
			if (n == 1)
				ret = reader->data_len;
			else
				ret = 0;
			pthread_mutex_unlock(&reader->fileunit->update_lock);
		}
		else
		{
			printf("NOOOOOOOOOOOOOOO\n");
		}

//		printf("mpegts_io_get_packet_count: 4\n");

		if (ret)
		{
			reader->packet_index += count;
			reader->packets_until_end = packets_left - count;
		}
//		printf("mpegts_io_get_packet_count: 5\n");

//		pthread_mutex_unlock(&reader->fileunit->update_lock);
	}
	return ret;
}


uint8_t mpegts_io_set_reader_sz_pos(MPEGTS_IO_READER_STRUCT *reader, uint64_t file_pos)
{
//	printf("mpegts_io_set_reader_sz_pos called\n");
	if (reader && reader->parent && reader->fileunit)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		uint64_t end = mpegts_io_get_reader_sz_endpos(reader);

//	printf("mpegts_io_set_reader_sz_pos 1\n");
		if (file_pos > end)
		{
		printf("mpegts_io_set_reader_sz_pos exit 1\n");
			return 0;
		}

//	printf("mpegts_io_set_reader_sz_pos 2\n");
		if (file_pos == 0)
		{
			reader->fileunit = mpegts_io->first_fileunit;
			reader->packet_index = 0;
			return 1;
		}

//	printf("mpegts_io_set_reader_sz_pos 3\n");

		if (mpegts_io && mpegts_io->first_fileunit)
		{
			uint64_t count = 0, last_count = 0, tmp_count = 0;
			MPEGTS_IO_FILEUNIT_STRUCT *funit = mpegts_io->first_fileunit;
			
//			while(funit != reader->fileunit)
			while(funit)
			{
				last_count = count;
				count += funit->current_file_size;
				if (file_pos < count)
				{
					uint64_t tmp = file_pos - last_count;
//					printf("Setting packetIndex: %"PRId64" (%"PRId64")\n", _idx_last->packet_number, _idx_last->packet_number* TS_PACKET_SIZE);
					reader->fileunit = funit;
					reader->packet_index = tmp/TS_PACKET_SIZE;
					return 1;
/*
					MPEGTS_IO_IDXUNIT_STRUCT *_idx =  funit->first_idx, *_idx_last = funit->first_idx;
					uint64_t tmp = file_pos - last_count;
					printf("HERE!! -- tmp_count: %" PRId64", tmp: %" PRId64", fpos: %" PRId64", last_count: %" PRId64"\n", tmp_count, tmp, file_pos, last_count);
					while(_idx)
					{
						printf("MOO: %" PRId64" (%" PRId64")\n", _idx->packet_number, _idx->packet_number * TS_PACKET_SIZE);
						if (_idx->packet_number * TS_PACKET_SIZE < tmp)
						{
							_idx_last = _idx;
							_idx = _idx->next;
						}
						else
						{
							printf("Setting packetIndex: %"PRId64" (%"PRId64")\n", _idx_last->packet_number, _idx_last->packet_number* TS_PACKET_SIZE);
							reader->fileunit = funit;
							reader->packet_index = _idx_last->packet_number;
							return 1;
						}
					}
					printf("Exit loop, sad\n");
*/
				}
				tmp_count++;
				funit = funit->next;
			}
		}
//		printf("mpegts_io_set_reader_sz_pos end\n");

	}
	return 0;
}
uint8_t mpegts_io_set_reader_pos(MPEGTS_IO_READER_STRUCT *reader, uint64_t dts)
{
	uint8_t ret = 0;

	if (reader && reader->parent)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		if (mpegts_io->cb_seek_to_time)
		{
			reader->fileunit = mpegts_io->first_fileunit;
			reader->packet_index = 1;
//			printf("mpegts_io_set_reader_pos cb\n");
			ret = (*mpegts_io->cb_seek_to_time)(reader, dts);
		}
		else
		{
//			printf("mpegts_io_set_reader_pos NO cb\n");
			MPEGTS_IO_IDXUNIT_STRUCT *_idx = NULL, *_idx2 = NULL;
			MPEGTS_IO_FILEUNIT_STRUCT *fileunit = mpegts_io->first_fileunit;
			MPEGTS_IO_FILEUNIT_STRUCT *tmpfileunit = reader->fileunit;
			pthread_mutex_lock(&mpegts_io->update_lock);

			reader->fileunit = mpegts_io->first_fileunit;
			reader->packet_index = 1;
//			printf("[TS_IO] mpegts_io_set_reader_pos: %lx (%" PRId64")\n", dts, dts);

			if (dts == 0)
			{
				ret = 1;
//				printf("[TS_IO] 1. get_reader, packet pos. start: %d\n", reader->packet_index);
			}

			if (dts == MPEGTS_IO_LIVE_POS)
			{
//				printf("HERE LIVE!\n");
				reader->fileunit = mpegts_io->current_fileunit;
				_idx = reader->fileunit->first_idx;

				while(_idx && _idx->next)
					_idx = _idx->next;

				if (_idx)
					reader->packet_index = _idx->packet_number;

				ret = 1;
//			printf("[TS_IO] 2. get_reader, packet pos. start: %d\n", reader->packet_index);
			}
			else if (dts > 0)
			{
//				MPEGTS_IO_FILEUNIT_STRUCT * f1 = NULL;
//				printf("Set Reader Pos: %" PRId64" (%0.4f)\n", dts, dts/90000.0);
				_idx2 = NULL;

				while(fileunit)
				{
//					printf("First1: %" PRId64" (%0.4f)\n", fileunit->first_idx->dts, fileunit->first_idx->dts/90000.0);
//					printf("First2: %" PRId64" (%0.4f)\n", fileunit->first_idx->pts, fileunit->first_idx->pts/90000.0);
//					printf("First2: %" PRId64" (%0.4f)\n", tmpfileunit ->first_idx->dts, fileunit->first_idx->dts/90000.0);
					if (dts <= fileunit->first_idx->dts)
					{
//						printf("FOUND!\n");
						_idx2 = fileunit->first_idx->next;
						// FOUND! 
						break;
					}
					else
					{
						_idx = fileunit->first_idx;
						while(_idx && _idx->next)
						{
//							printf("DTS: %" PRId64" (%0.4f) -- NDTS: %" PRId64" (%0.4f)\n", _idx->dts, _idx->dts/90000.0, _idx->next->dts, _idx->next->dts/90000.0);
							if (dts >= _idx->dts && dts < _idx->next->dts)
							{
//								printf("FOUND!! (%" PRId64" -- %" PRId64") -- %" PRId64"\n", _idx->dts, _idx->next->dts, _idx->packet_number);

								if (dts - _idx->dts < _idx->next->dts - dts)
								{
									_idx2 = _idx;
								}
								else
								{
									_idx2 = _idx->next;
								}
								break;
							}
							_idx = _idx->next;
						}
					}

					if (!_idx2)
					{
						fileunit = fileunit->next;
					}
					else
						break;
				}


				if (_idx2)
				{
//					printf("IDX2 (%" PRId64" -- %" PRId64")\n", _idx2->dts, _idx2->next->dts);
//					printf("Haz IDX2\n");
					ret = 1;


					if (tmpfileunit && fileunit && tmpfileunit != fileunit)
					{
						tmpfileunit->reader_count--;
						fileunit->reader_count++;
					}

					reader->fileunit = fileunit;
					reader->packet_index = _idx2->packet_number;
					if (reader->packet_index > 100)
						reader->packet_index -= 99;
//					printf("Setting fileunit to: %d (pindex: %" PRId64")\n", fileunit->id, reader->packet_index);
				}
				else
					printf("NoHaz IDX2\n");

//			printf("[TS_IO] 3. get_reader, packet pos. start: %" PRId64"\n", reader->packet_index);
//			printf("HMMMM: %" PRId64" (%0.4f)\n", mpegts_io_get_reader_pos(reader), mpegts_io_get_reader_pos(reader)/90000.0);
			}
			pthread_mutex_unlock(&mpegts_io->update_lock);
		}
	}
//	printf("mpegts_io_set_reader_pos ret: %d\n", ret);
	return ret;
}

uint64_t mpegts_io_get_reader_pos(MPEGTS_IO_READER_STRUCT *reader)
{
	if (reader && reader->fileunit)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;

		if (mpegts_io->cb_get_current_time)
		{
			return (*mpegts_io->cb_get_current_time)(reader);
		}
		else
		{
			MPEGTS_IO_IDXUNIT_STRUCT *_idx = reader->fileunit->first_idx;
			MPEGTS_IO_IDXUNIT_STRUCT *_idx2 = reader->fileunit->current_idx;
//			printf("Need PTS for packet index: %d\n", reader->packet_index);

			if (_idx && reader->packet_index <= _idx->packet_number)
				return _idx->dts;

			if (_idx2 && reader->packet_index >= _idx2->packet_number)
				return _idx2->dts;

			while(_idx)
			{
				if (_idx->next)
				{
//					printf("idx: %d, next: %d\n", _idx->packet_number, _idx->next->packet_number);

					if (reader->packet_index >= _idx->packet_number && reader->packet_index <= _idx->next->packet_number)
						return _idx->dts;
				}
				_idx = _idx->next;
			}
		}
	}
//		printf("None Found\n");
	return MPEGTS_IO_INVALID;
}

uint64_t mpegts_io_get_reader_sz_pos(MPEGTS_IO_READER_STRUCT *reader)
{
	if (reader && reader->parent && reader->fileunit)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		if (mpegts_io && mpegts_io->first_fileunit)
		{
			uint64_t ret = 0;
			MPEGTS_IO_FILEUNIT_STRUCT *funit = mpegts_io->first_fileunit;
			while(funit != reader->fileunit)
			{
				ret += funit->current_file_size;
				funit = funit->next;
			}
			ret += (reader->packet_index * TS_PACKET_SIZE);
			return ret;
		}
	}
	return MPEGTS_IO_INVALID;
}

uint64_t mpegts_io_get_reader_sz_startpos(MPEGTS_IO_READER_STRUCT *reader)
{
	return 0;
}

uint64_t mpegts_io_get_reader_sz_endpos(MPEGTS_IO_READER_STRUCT *reader)
{
	if (reader && reader->parent)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		if (mpegts_io && mpegts_io->first_fileunit)
		{
			uint64_t ret = 0;
			MPEGTS_IO_FILEUNIT_STRUCT *funit = mpegts_io->first_fileunit;
			while(funit)
			{
				ret += funit->current_file_size;
				funit = funit->next;
			}
			return ret;
		}
	}
	return MPEGTS_IO_INVALID;
}

uint64_t mpegts_io_get_reader_endpos(MPEGTS_IO_READER_STRUCT *reader)
{
	if (reader && reader->parent)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		if (mpegts_io->cb_get_end_time)
		{
			return (*mpegts_io->cb_get_end_time)(reader);
		}
		else if (mpegts_io->current_fileunit && mpegts_io->current_fileunit->current_idx)
		{
//			printf("mpegts_io_get_reader_endpos2, ret: %" PRId64"\n", mpegts_io->current_fileunit->current_idx->pts);
			return mpegts_io->current_fileunit->current_idx->pts;
		}
//		printf("mpegts_io_get_reader_endpos3\n");

	}
//	else
//		printf("mpegts_io_get_reader_endpos4\n");
	return MPEGTS_IO_INVALID;
}

uint64_t mpegts_io_get_reader_startpos(MPEGTS_IO_READER_STRUCT *reader)
{
	if (reader && reader->parent)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		if (mpegts_io->cb_get_start_time)
		{
			return (*mpegts_io->cb_get_start_time)(reader);
		}
		else if (mpegts_io->first_fileunit && mpegts_io->first_fileunit->current_idx)
		{
			return mpegts_io->first_fileunit->first_idx->pts;
		}
	}
	else
	{
		printf("[TS_IO] mpegts_io_get_reader_startpos: NO READER\n");
	}
	return MPEGTS_IO_INVALID;
}
uint64_t mpegts_io_get_reader_startpos2(MPEGTS_IO_READER_STRUCT *reader)
{
	if (reader && reader->parent)
	{
		MPEGTS_IO_STRUCT *mpegts_io = reader->parent;
		if (mpegts_io->cb_get_start_time)
		{
			return (*mpegts_io->cb_get_start_time)(reader);
		}
		else if (mpegts_io->first_fileunit && mpegts_io->first_fileunit->current_idx)
		{
			if (mpegts_io->first_fileunit->first_pts)
				return mpegts_io->first_fileunit->first_pts;
			else
				return mpegts_io->first_fileunit->first_idx->pts;
		}
	}
	else
	{
		printf("[TS_IO] mpegts_io_get_reader_startpos2: NO READER\n");
	}
//	printf("mpegts_io_get_reader_startpos2 end 3\n");
	return MPEGTS_IO_INVALID;
}

MPEGTS_IO_READER_STRUCT * mpegts_io_get_reader(MPEGTS_IO_STRUCT *mpegts_io, uint8_t type, uint64_t dts)
{
	MPEGTS_IO_READER_STRUCT * ret = calloc(1, sizeof(MPEGTS_IO_READER_STRUCT));

	if (ret)
	{
		uint8_t rc = 0;
		ret->parent = mpegts_io;

		switch (type)
		{
			case MPEGTS_IO_READ_START:
//				printf("M1\n");
				rc = mpegts_io_set_reader_pos(ret, 0);
			break;

			case MPEGTS_IO_READ_TIMECODE:
//				printf("TC2\n");
				rc = mpegts_io_set_reader_pos(ret, dts);
			break;

			case MPEGTS_IO_READ_LIVE:
//				printf("MOO: %lx %" PRId64"\n", MPEGTS_IO_LIVE_POS, MPEGTS_IO_LIVE_POS);
				rc = mpegts_io_set_reader_pos(ret, MPEGTS_IO_LIVE_POS);
			break;

		}
//		printf("mpegts_io_get_reader: %d -- %d\n", rc, !!ret->fileunit);
		pthread_mutex_lock(&mpegts_io->update_lock);
		if (rc && ret->fileunit)
		{
			if (mpegts_io->mode == MPEGTS_IO_MODE_SERVE)
			{
				MPEGTS_IO_FILEUNIT_STRUCT *_fileunit = mpegts_io->first_fileunit;
				while(_fileunit)
				{
					_mpegts_io_loadfile_idx(_fileunit);
					//_fileunit->current_file_size = get_file_size(_fileunit->ts_filename);
					_mpegts_io_loadfile_mpg(_fileunit);
					_fileunit = _fileunit->next;
				}
			}
			ret->fileunit->reader_count++;
		}
		else
		{
			free(ret);
			ret = NULL;
		}
		pthread_mutex_unlock(&mpegts_io->update_lock);
	}

	return ret;
}

int mpegts_io_add_data(MPEGTS_IO_STRUCT *mpegts_io, MPEGTS_IO_PACKET_STRUCT *packet)
{
	int ret = 0;
	MPEGTS_IO_FILEUNIT_STRUCT *fileunit = NULL;

	if (mpegts_io && packet && packet->data[0] == TS_SYNC_BYTE)
	{
		fileunit = mpegts_io->current_fileunit;

		if (!fileunit)
		{
			printf("[TS_IO] mpegts_io_add_data, bad1\n");
			return 1;
		}
/*
		if (fileunit->first_idx)
			printf("mpegts_io_add_data, IDX (%" PRId64"): %" PRId64", %" PRId64"\n", fileunit->first_pts, fileunit->first_idx->pts, fileunit->first_idx->dts);
		else
			printf("mpegts_io_add_data, First IDX NOT SET\n");
*/
		_mpegts_io_fileunit_update(fileunit, packet);

		if (mpegts_io->use_mem_only)
		{
			ret = _mpegts_io_write_ts_memory(fileunit, packet);
//			memcpy(fileunit->memory_handle + 
		}
		else
		{
			if (mpegts_io->mpegts_io_write_ts)
				ret = (*mpegts_io->mpegts_io_write_ts)(fileunit, packet);
			else
				ret = _mpegts_io_write_ts_nocache(fileunit, packet);
		}

	}
	return ret;
}


int8_t mpegts_io_close(MPEGTS_IO_STRUCT * mpegts_io, uint8_t remove)
{
	if (mpegts_io)
	{
		int i;
		MPEGTS_IO_FILEUNIT_STRUCT * fileunit  = mpegts_io->first_fileunit, * del = NULL;
//		printf("mpegts_io_close start\n");
		mpegts_io->islive = 0;

		if (mpegts_io->max_file_life)
			pthread_mutex_lock(&mpegts_io->update_lock);

//		printf("mpegts_io_close 1\n");
//		printf("Waiting for cleanup thread to die..\n");
		pthread_mutex_lock(&mpegts_io->update_lock);
//		printf("died..\n");

//		printf("mpegts_io_close 2\n");
		if (mpegts_io->base_filename)
			free(mpegts_io->base_filename);
//		printf("mpegts_io_close 3\n");

		if (mpegts_io->description)
			free(mpegts_io->description);
//		printf("mpegts_io_close 4\n");

		while(fileunit)
		{
			del = fileunit;
			_mpegts_io_destroy_fileunit(fileunit, remove);
			fileunit = fileunit->next;
			free(del);
		}
//		printf("mpegts_io_close 5\n");

		if (mpegts_io->write_cache)
			free(mpegts_io->write_cache);
//		printf("mpegts_io_close 6\n");


		for(i=0; i < MPEGTS_IO_FILEUNIT_EXTRA_COUNT;i++)
			if (mpegts_io->extra_data[i])
				utils_free_datapair(mpegts_io->extra_data[i]);
//		printf("mpegts_io_close 7\n");

		pthread_mutex_unlock(&mpegts_io->update_lock);

		if (mpegts_io->update_lock_attr)
			pthread_mutexattr_destroy(mpegts_io->update_lock_attr);
		pthread_mutex_destroy(&mpegts_io->update_lock);

		free(mpegts_io);
//		printf("mpegts_io_close 8\n");

//		printf("mpegts_io_close end\n");
	}
	return 0;
}

void *_mpegts_io_cleanup_thread(void * p)
{
	if (p)
	{
		uint64_t time_life = 0;
		double time_life_s = 0;
		MPEGTS_IO_STRUCT * mpegts_io = (MPEGTS_IO_STRUCT *)p;
		MPEGTS_IO_FILEUNIT_STRUCT * first_unit = mpegts_io->first_fileunit;
		MPEGTS_IO_FILEUNIT_STRUCT * current_unit= NULL, *del_unit = NULL;

		while (mpegts_io->islive)
		{
			if (first_unit && first_unit->first_idx && first_unit->last_idx)
			{
				current_unit = mpegts_io->current_fileunit;

				if (current_unit && current_unit->current_idx)
				{
//					current_pts = current_unit->current_idx->pts;
					time_life = current_unit->current_idx->pts - first_unit->last_idx->pts;
					time_life_s = time_life/90000.0;

//					printf("Cleanup, CurrentTime: %0.2f, FirstTime: %0.2f (Max: %d, RCount: %d)\n", current_pts/90000.0, first_unit->last_idx->pts/90000.0, mpegts_io->max_file_life,  first_unit->reader_count);
					if (time_life_s > mpegts_io->max_file_life)
					{
						if (first_unit->reader_count == 0)
						{
							pthread_mutex_lock(&mpegts_io->update_lock);
							del_unit = first_unit;
							mpegts_io->first_fileunit = mpegts_io->first_fileunit->next;

							_mpegts_io_destroy_fileunit(del_unit, 1);
							free(del_unit);
/*
							printf("FILEUNIT CLEANUP!!\n");
							printf("READER COUNT: %d\n", first_unit->reader_count);
*/
							pthread_mutex_unlock(&mpegts_io->update_lock);
						}
						else
						{
//							printf("Should Cleanup but reader is still attached\n");
						}
					}
//					printf("Clean thread...: %" PRId64" (%0.4f) -- %"PRId64" (%0.4f)  -- %" PRId64" (%0.4f) ## %" PRId64" (%0.4f)\n", first_unit->first_idx->pts,first_unit->first_idx->pts/90000.0, first_unit->last_idx->pts,first_unit->last_idx->pts/90000.0, current_pts, current_pts/90000.0, time_life, time_life/90000.0);

				}

			}
			usleep(mpegts_io->cleanup_wait_time * 1000);
			first_unit = mpegts_io->first_fileunit;
		}
//		printf("MOO\n");
		pthread_mutex_unlock(&mpegts_io->update_lock);
		mpegts_io->cleanup_thread = 0;
	}
	printf("[TS_IO] cleanup thread ended\n");
	return NULL;
}

void *_mpegts_io_fixidx_thread(void * p)
{
	if (p)
	{
		char *filename = (char*)p;
//		printf("[TS_IO] Fix IDX thread started, base file: %s\n", filename);
		mpegts_io_regen_idx(filename, 0, 0);
		printf("[TS_IO] Fix IDX thread ended: %s\n", filename);
		free(p);
	}
	return NULL;
}

int mpegts_io_disconnect_reader(MPEGTS_IO_READER_STRUCT *reader)
{
	int ret = -1;
	if (reader && reader->fileunit)
	{
		reader->fileunit->reader_count--;
		ret = reader->fileunit->reader_count;
	}
	return ret;
}

//MPEGTS_IO_PACKET_STRUCT *mpegts_io_parse_packet(uint8_t *data, uint32_t data_size)
MPEGTS_IO_PACKET_STRUCT *mpegts_io_parse_packet(uint8_t *data, uint32_t data_size, MPEGTS_IO_PACKET_STRUCT *pass)
{
	MPEGTS_PACKET *save = NULL;
	MPEGTS_IO_PACKET_STRUCT *packet = NULL;
//	printf("mpegts_io_parse_packet -- start\n");

	if (data && data_size)
	{
		BITSTREAM *bs = NULL;
		int q = 0;

		if (!pass)
		{
			packet = calloc(1, sizeof(MPEGTS_IO_PACKET_STRUCT));
		}
		else
		{
			save = pass->packet;
			packet = pass;
		}

		if (!packet)
			data_size = 0;

		memset(packet, 0, sizeof(MPEGTS_IO_PACKET_STRUCT));

		if (save)
			packet->packet = save;

		for (q=0; q < data_size; q+= TS_PACKET_SIZE)
		{
			if (data[q] == TS_SYNC_BYTE)
			{
				bs = bits_create(&data[q], TS_PACKET_SIZE);
				if (bs)
				{
					packet->data = &data[q];
					packet->data_len = TS_PACKET_SIZE;
//					MPEGTS_PACKET * p = mpegts_parse_packet2(bs, 0);
					MPEGTS_PACKET * p = NULL;

					if (pass->packet)
						p = pass->packet;
					else
						p = mpegts_parse_packet2(bs, 0);

					if (p)
					{
						packet->pid = p->pid;

						if (packet->pid == PAT_PID)
						{
/*
							if (p->pat)
							{
								packet->pat = mpegts_dup_pat(p->pat);
								//packet->pat = calloc(1, sizeof(MPEGTS_PAT));
								//memcpy(packet->pat, p->pat, sizeof(MPEGTS_PAT));
								mpegts_free_pat(p->pat);
							}
*/
						}
						else if (p->payload_start && p->payload_start_struct)
						{
							if ((uint8_t)p->type > TID_PMT)
							{
//								uint8_t _type = (uint8_t)p->type;
//								printf("[TS_IO] NOT Setting PTS/DTS to zero: 0x%x\n", p->type);
//								printf("NOT Stting PID: 0x%x, P: %" PRId64", D: %" PRId64"\n", p->pid, p->payload_start_struct->pts, p->payload_start_struct->dts);

								packet->stream_type = p->payload_start_struct->stream_id;
								packet->adapt = p->adapt_field_control;
//								printf("moo? 0x%x\n", (uint8_t) packet->stream_type);
/*
								if (packet->set_video_pid)
								{
									if (_type >= MPEGTS_VIDEO_STREAM_START && _type <= MPEGTS_VIDEO_STREAM_END)
										ts_io->video_pid = p->pid;
								}
*/
//								packet->frame_type = p->frame_type;
								packet->start = p->payload_start;
								packet->pts =  p->payload_start_struct->pts;
								packet->dts =  p->payload_start_struct->dts;
//								printf("POO: 0x%x, %" PRId64", %" PRId64"\n", packet->stream_type, p->payload_start_struct->pts, p->payload_start_struct->dts);
							}
							else
							{
								printf("[TS_IO] Setting PTS/DTS to zero: 0x%x\n", p->type);
								packet->pts = packet->dts = 0;
							}
						}
						if (!pass->packet)
							mpegts_free_packet(p);
					}
					free(bs);
				}
			}
			else
			{
//				printf("NO SYNC BYTE\n");
			}
		}
	}

//	printf("mpegts_io_parse_packet -- end\n");
	return packet;
}


//int mpegts_io_free_recordings(char *basedir, MPEGTS_IO_RECORDINGS_STRUCT *recs)


void mpegts_io_cleanup_recordings(char *basedir)
{
	if (basedir)
	{
		DIR * dir = opendir(basedir);

		if (dir)
		{
			struct dirent *dp = NULL;
			char tmp_fname[MAX_FILENAME_SIZE] = {0};
			char tmp_fname2[MAX_FILENAME_SIZE] = {0};

			printf("[TS_IO] Cleaning up regen files...\n");
			while ((dp = readdir(dir)) != NULL)
			{
				if (dp->d_name)
				{
					char * filename = dp->d_name;
					uint32_t filename_len = strlen(filename);

					if (filename_len > 4)
					{

						if (filename[filename_len-4] == '.' && filename[filename_len-3] == MEPGTS_IO_REGEN_EXT[0] &&
							filename[filename_len-2] == MEPGTS_IO_REGEN_EXT[1] && filename[filename_len-1] == MEPGTS_IO_REGEN_EXT[2])
						{
							snprintf(tmp_fname, MAX_FILENAME_SIZE - 1, "%s/%s", basedir, filename);

							printf("[TS_IO] DEL1:\t%s\n", tmp_fname);

							remove(tmp_fname);
						}
						else if (filename[filename_len-4] == '.' && filename[filename_len-3] == 'r' &&
									filename[filename_len-2] == 'e' && filename[filename_len-1] == 'c')
						{
							char * t3 = strdup(filename);
							uint32_t t3_len = 0;

							if (t3)
							{
								snprintf(tmp_fname2, MAX_FILENAME_SIZE - 1, "%s/%s", basedir, t3);
								t3_len = strlen(tmp_fname2);

								tmp_fname2[t3_len-3] = 'i';
								tmp_fname2[t3_len-2] = 'd';
								tmp_fname2[t3_len-1] = 'x';


								free(t3);
								if (file_exists(tmp_fname2) == 0 && get_file_size(tmp_fname2) < 300)
								{
									printf("[TS_IO] DEL2:\t%s\n", tmp_fname2);
									remove(tmp_fname2);
								}

								if (file_exists(tmp_fname2) == -1)
								{
									pthread_t tid = 0;
									char *pass = NULL;
									tmp_fname2[t3_len-4] = '\0';

									pass = strdup(tmp_fname2);
									pthread_create(&tid, NULL, _mpegts_io_fixidx_thread, (void*)pass);

//									_mpegts_io_fixidx_thread(pass);
								}

							}
						}


					}
				}
			}
			printf("[TS_IO] Cleaning up regen files done!\n");
			closedir(dir);
		}
	}
	return;
}

MPEGTS_IO_RECORDINGS_STRUCT * mpegts_io_load_recordings(char *basedir, MPEGTS_IO_RECORDINGS_STRUCT *recs)
{
//	printf("mpegts_io_load_recordings start\n");
	MPEGTS_IO_RECORDINGS_STRUCT * ret = calloc(1, sizeof(MPEGTS_IO_RECORDINGS_STRUCT));

	if (ret)
	{
		MPEGTS_IO_STRUCT  *first = NULL, *del = NULL;
		DIR * dir = opendir(basedir);

		if (recs)
		{
			ret->sequence_num = recs->sequence_num;
			first = recs->first_io_struct;

			while(first)
			{
				first->reused = 0;
				first->next2 = first->next;
				first = first->next;
			}
		}

		if (!ret->sequence_num)
			ret->sequence_num = 1;

		if (dir)
		{
			struct dirent *dp = NULL;
//			printf("[TS_IO] Loading Recordings from dir: %s\n", basedir);

			while ((dp = readdir(dir)) != NULL)
			{
				if (dp->d_name)
				{
					char * filename = dp->d_name;
					uint32_t filename_len = strlen(filename);

					if (filename_len > 4)
					{
//						int8_t file_there  = 0;
						off_t file_size = 0;
						char tmp_fname[MAX_FILENAME_SIZE] = {0};
						char *c1 = strndup(filename, filename_len-4);

						snprintf(tmp_fname, MAX_FILENAME_SIZE - 1, "%s/%s.idx", basedir, c1);

//						printf("processing1: %s\n", tmp_fname);

						// Probably a recording in action
						if (file_exists(tmp_fname) == 0)
						{
							file_size = get_file_size(tmp_fname);
							if (file_size == 0)
							{
								snprintf(tmp_fname, MAX_FILENAME_SIZE - 1, "%s/%s", basedir, c1);
								mpegts_io_regen_idx(tmp_fname, 0, 3);
								snprintf(tmp_fname, MAX_FILENAME_SIZE - 1, "%s/%s.idx", basedir, c1);
								file_size = get_file_size(tmp_fname);
								printf("[TS_IO] idx len is 0, re-gen idx (rec?): %s, new idx sz: %" PRId64"\n", c1, file_size);
							}
						}
						else
							file_size = 0;

//						printf("Testing for idx: %s (%" PRId64") -- %s %s [%c %c %c %c]\n", tmp_fname, file_size, c1, filename, filename[filename_len-4], filename[filename_len-3], filename[filename_len-2], filename[filename_len-1]);
//						if (c1 && file_size > 1024 &&
						if (c1 && file_size &&
								filename[filename_len-4] == '.' && filename[filename_len-3] == 'r' &&
								filename[filename_len-2] == 'e' && filename[filename_len-1] == 'c')
						{
							MPEGTS_IO_STRUCT *ts_io = NULL;
							snprintf(tmp_fname, MAX_FILENAME_SIZE - 1, "%s/%s", basedir, c1);
//						printf("processing2: %s\n", tmp_fname);

							if (recs)
							{
//								printf("we have recs\n");

//								MPEGTS_IO_STRUCT *first = recs->first_io_struct;
								first = recs->first_io_struct;

								while(first)
								{
//									printf("CMP: %s -- %s\n", first->base_filename, tmp_fname);
									if (strncmp(first->base_filename, tmp_fname, MAX_FILENAME_SIZE) == 0)
									{
//										ts_io = calloc(1, sizeof(*ts_io));
//										memcpy(ts_io, first, sizeof(MPEGTS_IO_STRUCT));
										ts_io = first;
										break;
									}
									first = first->next2;
								}
							}

							if (ts_io)
							{
//								printf("we have ts_io\n");
								MPEGTS_IO_FILEUNIT_STRUCT *_fileunit = ts_io->first_fileunit;
								ts_io->next = NULL;
								ts_io->reused = 1;

								while(_fileunit)
								{
//									printf("_mpegts_io_loadfile_idx\n");
									_mpegts_io_loadfile_idx(_fileunit);
									_fileunit = _fileunit->next;
								}
							}
							else
							{
//								printf("we have no ts_io\n");

								MPEGTS_IO_INIT_ARGS_STRUCT *ts_io_args = calloc(1, sizeof(MPEGTS_IO_INIT_ARGS_STRUCT));

								if (ts_io_args)
								{
//									printf("[TS_IO] Recorded Item: %s [idx, mpg, rec]\n", tmp_fname);

									ts_io_args->filename_base = tmp_fname;
									ts_io_args->mode = MPEGTS_IO_MODE_SERVE;
									ts_io = mpegts_io_init(ts_io_args);
									ts_io->reused = 1;
									free(ts_io_args);
									ret->sequence_num++;
								}
							}

							if (ts_io)
							{
								ts_io->id = ret->count+1;
//								printf("[TS_IO] mpegts_io_init is good: %d\n", ts_io->id);

								if (!ret->first_io_struct)
								{
									ret->first_io_struct = ret->current_io_struct = ts_io;
								}
								else
								{
									 ret->current_io_struct->next = ts_io;
									 ret->current_io_struct = ts_io;
								}
								ret->count++;
							}
//							else
//								printf("[TS_IO] mpegts_io_init is NULL!\n");
						}

						if (c1)
							free(c1);

					}
				}
			}

			if (recs)
			{
				first = recs->first_io_struct;
				del = NULL;
				while(first)
				{
					del = first;
//					printf("HMM4: %s (%d)\n", first->base_filename, first->reused);
					first = first->next2;
					if (del && !del->reused)
					{
//						printf("Freeing\n");
						mpegts_io_close(del, 0);
						if (ret->sequence_num == recs->sequence_num)
							ret->sequence_num++;
					}
				}
//				free(recs);
			}

			closedir(dir);
		}
		else
		{
			printf("[IO] Problem: %s\n", strerror(errno));
		}
	}
//	printf("mpegts_io_load_recordings end\n");
	return ret;
}

MPEGTS_IO_STRUCT * mpegts_io_init(MPEGTS_IO_INIT_ARGS_STRUCT *args)
{
	if (!args)
		return NULL;


	MPEGTS_IO_STRUCT * ret = calloc(1, sizeof(MPEGTS_IO_STRUCT));
	if (ret)
	{
		ret->cb_seek_to_time = args->cb_seek_to_time;
		ret->cb_get_current_time = args->cb_get_current_time;
		ret->cb_get_start_time = args->cb_get_start_time;
		ret->cb_get_end_time = args->cb_get_end_time;
		ret->extra_data2 = args->extra_data2;

		if (args->stream_only)
		{
			ret->use_mem_only = 1;
			ret->max_file_size = 106383 * 188;
			ret->max_file_life = 10;
		}
		else
		{
			ret->max_file_size = args->max_segment_size;
			ret->max_file_life = args->max_segment_life;
		}

		if (args->cleanup_wait_time)
			ret->cleanup_wait_time = args->cleanup_wait_time;
		else
			ret->cleanup_wait_time = 1000;

//		ret->update_lock_attr = calloc(1, sizeof(*ret->update_lock_attr));
		utils_mutex_init(&ret->update_lock, ret->update_lock_attr, PTHREAD_MUTEX_RECURSIVE);
//		utils_mutex_init(&ret->update_lock, NULL, PTHREAD_MUTEX_RECURSIVE);
//		printf("[TS_IO] init, max segment size: %d\n", ret->max_file_size);
		ret->base_filename = strdup(args->filename_base);
		ret->mode = args->mode;

		switch (args->mode)
		{
			case MPEGTS_IO_MODE_CREATE:
//				ret->base_filename = strdup(args->filename_base);
				ret->first_fileunit = ret->current_fileunit = calloc(1, sizeof(MPEGTS_IO_FILEUNIT_STRUCT));
				ret->first_fileunit->max_file_size = ret->max_file_size;
				ret->islive = 1;
				ret->isrecording = args->recording;
				ret->first_fileunit->parent = ret;
				ret->write_cache = NULL;

				ret->write_cache_size = args->write_cache_size;

				if (!args->stream_only && ret->write_cache_size)
				{
					if (ret->write_cache_size % TS_PACKET_SIZE)
					{
						ret->write_cache_size = (ret->write_cache_size/TS_PACKET_SIZE) * TS_PACKET_SIZE;
					}
					printf("[TS_IO] fwrite cache of: %d bytes\n", ret->write_cache_size);
					ret->write_cache = malloc(ret->write_cache_size);
					ret->mpegts_io_write_ts = _mpegts_io_write_ts_cache;
				}

				if (ret->max_file_life)
				{
//					printf("[TS_IO] max_file_life is: %d\n", ret->max_file_life);
					pthread_create(&ret->cleanup_thread, NULL, _mpegts_io_cleanup_thread, (void*)ret);
				}
				else
				{
//					printf("[TS_IO] NOT deleting files\n");
				}
			break;

			case MPEGTS_IO_MODE_SERVE:
			{
				MPEGTS_IO_FILEUNIT_STRUCT * tmp_fileunit  = calloc(1, sizeof(MPEGTS_IO_FILEUNIT_STRUCT));

				tmp_fileunit->parent = ret;
				tmp_fileunit->rec_filename = calloc(1, MAX_FILENAME_SIZE);
				tmp_fileunit->idx_filename = calloc(1, MAX_FILENAME_SIZE);
				tmp_fileunit->ts_filename = calloc(1, MAX_FILENAME_SIZE);

				snprintf(tmp_fileunit->rec_filename, MAX_FILENAME_SIZE -1, "%s.rec", args->filename_base);
				snprintf(tmp_fileunit->idx_filename, MAX_FILENAME_SIZE -1, "%s.idx", args->filename_base);
				snprintf(tmp_fileunit->ts_filename, MAX_FILENAME_SIZE -1, "%s.mpg", args->filename_base);

				if (_mpegts_io_loadfile_idx(tmp_fileunit) != 0)
				{
					printf("BAD1\n");
					return NULL;
				}

				if (_mpegts_io_loadfile_mpg(tmp_fileunit) != 0)
				{
					printf("BAD2\n");
					return NULL;
				}

				if (_mpegts_io_loadfile_rec(tmp_fileunit) != 0)
				{
					printf("BAD3\n");
					return NULL;
				}

				ret->first_fileunit  = ret->current_fileunit = tmp_fileunit;
			}
			break;
		}
	}
	return ret;
}

#ifdef _MAIN_

#define MAX_SEGMENT_SIZE				(104340000 *2)

char * input_file = NULL;
uint8_t mode = MPEGTS_IO_MODE_SERVE;

static const char *optString = "m:i:?h";

static const struct option longOpts[] =
{
	{ "input", required_argument, NULL, 'i' },
	{ "mode",  required_argument, NULL, 'm' },
	{ "help", no_argument, NULL, 'h' },
	{ NULL, no_argument, NULL, 0 }
};

void display_usage(char *exe)
{
	fprintf(stderr,"bleah\n");
}

uint8_t get_opts(int argc, char *const argv[])
{
	int index = 0;
	int opt = getopt_long( argc, argv, optString, longOpts, &index );

	if (opt == -1 )
	{
		display_usage(argv[0]);
		return 1;
	}

	while ( opt != -1 )
	{
		switch ( opt )
		{
			case 'm':
				mode = atoi(optarg);
				break;

			case 'i':
				input_file = strdup(optarg);
//				printf("HERE: %c\n", input_file[strlen(input_file)-1]);
				if (input_file[strlen(input_file)-1] == '/')
					input_file[strlen(input_file)-1] = '\0';
				break;

			case 'h': /* fall-through is intentional */
			case '?':
				display_usage(argv[0]);
				break;

			default:
				/* You won't actually get here. */
				break;
		}
		opt = getopt_long( argc, argv, optString, longOpts, &index );
	}
	return 0;
}

int main(int argc, char *argv[])
{
	if (!get_opts(argc, argv) && input_file)
	{
//		MPEGTS_IO_STRUCT * ts_io = NULL;

		switch (mode)
		{
			case MPEGTS_IO_MODE_CREATE:
			{
			}
			break;

			case MPEGTS_IO_MODE_REGEN_IDX_FIRST:
			{
				printf("REGEN, first: %s\n", input_file);
				mpegts_io_regen_idx(input_file, 1, 2);
			}
			break;

			case MPEGTS_IO_MODE_REGEN_IDX:
			{
				printf("REGEN: %s\n", input_file);
				mpegts_io_regen_idx(input_file, 1, 0);
			}
			break;

			case MPEGTS_IO_MODE_SERVE:
			{
/*
				MPEGTS_IO_RECORDINGS_STRUCT * recs = mpegts_io_load_recordings(input_file);
				if (recs)
				{
					MPEGTS_IO_STRUCT * tmpio = recs->first_io_struct, *del;
					printf("YAY: %d\n", recs->count);

					while(tmpio)
					{
						del = tmpio;
						tmpio = tmpio->next;
						mpegts_io_close(del, 0);
					}
				}
				else
				{
					printf("NO :(\n");
				}
*/
			}
			break;

			default:
			break;
		}
	}
	return 0;
}

#endif
	
